package com.marketlive.system.config.filesystem;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.apache.commons.lang.StringUtils;
import com.marketlive.system.config.ConfigurationManager;
import com.marketlive.system.config.ConfigurationBranch;
import com.marketlive.system.config.bundle.BundleLoader;

import java.io.File;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.ResourceBundle;
import java.util.PropertyResourceBundle;


/**
 * Loads the configuration from a file system starting from the given root directory and
 * processing each directory and file according to the rules.
 */
public class FileSystemLoader {

    /**
     * Logger
     */
    private static Log log = LogFactory.getLog(FileSystemLoader.class);

    /**
     * Semicolon-separated list of files and/or directories to ignore.
     * Files or directories with names matching the ignore list are not loaded.
     */
    private String ignoreList;

    /**
     * Loads configuration from the given root using the specified <code>ConfigurationManager</code>.
     * 
     * @param configMgr the <code>ConfigurationManager</code> to use
     * @param rootDirectory a <code>File</code> pointing to the directory to use
     */
    public void loadFromFileSystem( ConfigurationManager configMgr, File rootDirectory) {
    	//System.out.println("FileSystemLoader::loadFromFileSystem(): rootDirectory=" + rootDirectory +"'");
        loadFromFileSystem( (ConfigurationBranch) configMgr.getRoot(), rootDirectory);
    }

    /**
     * Loads the specified directory into the specified branch.
     * 
     * @param configBranch the <code>ConfigurationBranch</code> to load into
     * @param directory a <code>File</code> pointing to the directory to use
     */
    public void loadFromFileSystem( ConfigurationBranch configBranch, File directory) {
        File[] files = directory.listFiles();

        if (files==null) {
            throw new IllegalArgumentException("Invalid directory: " + directory );
        }

        for (int i=0; i < files.length;i++) {
            File subFile = files[i];
            
            if (".svn".equals(subFile.getName())) {
                continue;
            }
            
            log.debug( "processing entry: " + subFile.getPath());
            //System.out.println("processing entry: "  + subFile.getPath());
            if (ignoreList!=null && StringUtils.contains(ignoreList,subFile.getName())) {
                log.info( " In ignore list, skipping: " + subFile.getPath());
            }
            else if (subFile.isDirectory()) {
            	//System.out.println("loadFromFileSystem( ): subFile.getName() = '" + subFile.getName() + "'");
                // use directory name to get branch
                ConfigurationBranch subBranch =
                        (ConfigurationBranch) configBranch.getBranch( subFile.getName(), true);
                // load starting at that branch
                loadFromFileSystem(subBranch, subFile);
            }
            else if (subFile.getName().endsWith(".properties")) {
                String name = StringUtils.substringBeforeLast(subFile.getName(),".properties");
                String path = StringUtils.substringBeforeLast(subFile.getPath(),".properties");

                ConfigurationBranch subBranch =
                    (ConfigurationBranch) configBranch.getBranch( name, true);

                // load property bundle
                log.debug("Load bundle " + path + " to branch: " + subBranch);
                try {
                    BundleLoader.loadBundle(subBranch, getBundle(subFile));
                }
                catch (Exception fnfe) {
                    throw new RuntimeException("Could not load property file:" + subFile.getPath(), fnfe);
                }
            }
        }
    }


    /**
     * Returns a <code>ResourceBundle</code> from the specified <code>File</code>.
     * @param bundleFile a <code>File</code> pointing to the bundle
     * @return the <code>ResourceBundle</code> from the file 
     * @throws Exception if bundleFile is not defined or cannot be accessed
     */
    private ResourceBundle getBundle(File bundleFile) throws Exception {
        //todo: need to allow for localization via locale
        ResourceBundle bundle = new PropertyResourceBundle( new BufferedInputStream( new FileInputStream(bundleFile)));
        return bundle;
    }

    /**
     * Returns the string containing a semicolon-separated list of files and directories to ignore.
     * 
     * @return a <code>String</code> containing a semicolon-separated list
     */
    public String getIgnoreList() {
        return ignoreList;
    }

    /**
     * Sets the semicolon-separated list of files and directories to ignore when loading.
     * 
     * @param ignoreList a <code>String</code> containing a list of files and directories to ignore
     */
    public void setIgnoreList(String ignoreList) {
        this.ignoreList = ignoreList;
    }
}
